home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / sound / pci sound input driver / pcisoundinputdriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  64.6 KB  |  1,821 lines

  1. /*
  2.     File:        PCISoundInputDriver.c
  3.  
  4.     Contains:    Sample PCI sound input hardware driver
  5.  
  6.     Written by: Mark Cookson    
  7.  
  8.     Copyright:    Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 8/3/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23.  
  24. #include <Aliases.h>
  25. #include <DriverServices.h>
  26. #include <DriverGestalt.h>
  27. #include <NameRegistry.h>
  28. #include <Resources.h>
  29. #include <Sound.h>
  30. #include <SoundInput.h>
  31. #include <TextUtils.h>
  32. #include <Timer.h>
  33.  
  34. #include <stdio.h>
  35. #include <Strings.h>
  36.  
  37. // This is what our input parameter looks like
  38. #pragma options align=mac68k
  39. struct SoundParam {
  40.     QElemPtr                        qLink;
  41.     short                            qType;
  42.     short                            ioTrap;
  43.     Ptr                                ioCmdAddr;
  44.     IOCompletionUPP                    ioCompletion;
  45.     OSErr                            ioResult;
  46.     StringPtr                        ioNamePtr;
  47.     short                            ioVRefNum;
  48.     short                            ioCRefNum;
  49.     short                            csCode;
  50.     short                            csParam[11];
  51. };
  52. typedef struct SoundParam SoundParam, *SoundParamPtr;
  53. #pragma options align=reset
  54.  
  55. // tell the OS all about us
  56.  
  57. extern DriverDescription TheDriverDescription = {
  58.   kTheDescriptionSignature,
  59.   kInitialDriverDescriptor,
  60.   // DriverType
  61.   "\pTestSoundInputDriver",
  62.   1, 0, developStage, 1,
  63.   // DriverOSRuntimeInfo
  64.   0
  65.   | (1 * kDriverIsLoadedUponDiscovery)        /* Loader runtime options */
  66.   | (1 * kDriverIsOpenedUponLoad)            /* Opened when loaded */
  67.   | (0 * kDriverIsUnderExpertControl)        /* No I/O expert to handle loads/opens */
  68.   | (0 * kDriverIsConcurrent)                /* Not concurrent yet */
  69.   | (0 * kDriverQueuesIOPB),                /* Not internally queued yet */
  70.   "\p.TestSoundInputDriver",                /* Str31 driverName (OpenDriver param) */
  71.   0, 0, 0, 0, 0, 0, 0, 0,                    /* UInt32 driverDescReserved[8] */
  72.   // DriverOSService
  73.   1,                                        /* ServiceCount nServices */
  74.   // DriverServiceInfo
  75.   kServiceCategoryNdrvDriver,                /* OSType serviceCategory */
  76.   kNdrvTypeIsGeneric,                        /* OSType serviceType */
  77.      1, 0, developStage, 1,                    /* major, minor, stage, rev */
  78. };
  79.  
  80. //For debugging information
  81. #define DEBUG        0
  82. #define DEBUG2        0
  83. #define FULLDEBUG    0
  84.  
  85. #define kSamplesInBuffer    1024
  86. #define    kSilence            128
  87. #define    kAmplitude            75
  88.  
  89. #define    kSquareSource        1
  90. #define    kSawSource            2
  91. #define    kSilenceSource        3
  92.  
  93. #define kNumRates            3
  94. #define kNumSizes            2
  95. #define kNumCompressions    1
  96.  
  97. typedef struct myTMTask {
  98.     TMTask        theTask;
  99.     ParmBlkPtr    pb;
  100. } myTMTask;
  101.  
  102.  
  103. //----------------------------------------------------------------------------------
  104. //                                    Function Prototypes
  105. //----------------------------------------------------------------------------------
  106.  
  107. pascal OSErr FragInit                (CFragInitBlockPtr initInfo);
  108. pascal void FragTerm                (void);
  109.  
  110. static OSStatus DriverKillIOCmd     (ParmBlkPtr pb);
  111. extern OSErr DoDriverIO                (AddressSpaceID addressSpaceID, IOCommandID ioCommandID, IOCommandContents ioCommandContents, IOCommandCode ioCommandCode, IOCommandKind ioCommandKind);
  112.  
  113. static pascal void HWIntProc        (QElemPtr passedPtr);
  114. static void MakeSquareWave            (long duration, long numberSamples, UnsignedFixed sampleRate, long frequency, short sampleSize, short numChannels);
  115. static void MakeSawWave                (long duration, long numberSamples, UnsignedFixed sampleRate, long frequency, short sampleSize, short numChannels);
  116. static OSErr DoOptionsDialog        (void);
  117. static void SetHardwareToDefault    (void);
  118.  
  119.  
  120. //----------------------------------------------------------------------------------
  121. //                                    Globals
  122. //----------------------------------------------------------------------------------
  123.  
  124. //Hardware specific globals
  125. SInt16            gContinuousOn,
  126.                 gLevelMeterOn,
  127.                 gTwosComplementOn,
  128.                 gAGCOn,
  129.                 gPlayThruVolume,
  130.                 gVoxRecordingOn,
  131.                 gVoxStoppingOn,
  132.                 gPauseState,
  133.                 gNumberChannels,
  134.                 gSampleSize,
  135.                 gVOXStartTrigger,
  136.                 gVOXStopTrigger,
  137.                 gVOXDelay,
  138.                 gCompressionFactor,
  139.                 gCurrentInputSource        = kSquareSource;
  140. SInt32            gActiveChannels;            //channels to record from 0x01 == only left, 0x02 == only right, 0x03 == both channels
  141. UnsignedFixed    gSampleRate;
  142. Fixed            gInputGain,
  143.                 gLeftInputGain,
  144.                 gRightInputGain;
  145. OSType            gCompressionType,
  146.                 gRecordingQuality;
  147. SIInterruptUPP    gUserInterruptProc        = nil;
  148.  
  149. //Globals needed to simulate our hardware
  150. myTMTask        gSimulatedHWInterrupt;
  151. TimerUPP        gSimulatedHWIntProc        = nil;
  152. SInt32            gInterruptFreq            = 0,
  153.                 gSamplesWritten            = 0;
  154. SInt16            gNextSaw16Sample        = -((kAmplitude * 0.01) * 32767);    //starting point for saw tooth wave
  155. SInt8            gNextSaw8Sample            = kSilence - kAmplitude;    //starting point for saw tooth wave
  156. Ptr                gSoundBuffer            = nil;    //our hardware's internal buffer
  157.                                                 
  158. //Driver specific globals
  159. Boolean            gStopRecording            = false;
  160. DriverRefNum    gDrvrRefNum;
  161. Handle            gDrvrIcon,
  162.                 gInputSourceNames;
  163. AliasHandle        gAliasToDriver;
  164. StringHandle    gDriverName;
  165.  
  166. //----------------------------------------------------------------------------------
  167. //                                    CFM Init
  168. //----------------------------------------------------------------------------------
  169.  
  170. pascal OSErr FragInit (CFragInitBlockPtr initInfo) {
  171.     Handle                iconHandle,
  172.                         strHandle;
  173.     StringHandle        driverName;
  174.     SInt16                resRefNum;
  175.     OSErr                err            = noErr;
  176.  
  177.     if (initInfo->fragLocator.where == kDataForkCFragLocator || initInfo->fragLocator.where == kResourceCFragLocator) {
  178.         resRefNum = FSpOpenResFile (initInfo->fragLocator.u.onDisk.fileSpec, fsRdPerm);
  179.         err = ResError();
  180.         if (err != noErr) {
  181.         #if DEBUG
  182.             SysDebugStr ("\p!!Error returned from FSpOpenResFile!!");
  183.         #endif
  184.         }
  185.  
  186.         if (resRefNum == -1) {
  187.         #if DEBUG
  188.             SysDebugStr ("\p!!Error resRefNum is -1!!");
  189.         #endif
  190.         }
  191.     }
  192.  
  193.     if (resRefNum != -1 && err == noErr) {
  194.         iconHandle = Get1Resource ('ICN#', 128);
  195.         err = ResError ();
  196.         if (iconHandle == nil) {
  197.         #if DEBUG
  198.             SysDebugStr ("\p!!iconHandle is nil!!");
  199.         #endif
  200.         }
  201.  
  202.         if (err != noErr) {
  203.         #if DEBUG
  204.             SysDebugStr ("\p!!Error from Get1Resource('ICN#', 128)!!");
  205.         #endif
  206.         }
  207.  
  208.         if (iconHandle != nil) {
  209.             gDrvrIcon = NewHandleSys (GetHandleSize (iconHandle));
  210.             BlockMoveData (*iconHandle, *gDrvrIcon, GetHandleSize (iconHandle));
  211.             ReleaseResource (iconHandle);
  212.         } else if (err == noErr) {
  213.             err = resNotFound;
  214.         #if DEBUG
  215.             SysDebugStr ("\p!!Error Get1Resource('ICN#', 128), resNotFound!!");
  216.         #endif
  217.         }
  218.  
  219.         strHandle = Get1Resource ('STR#', 128);
  220.         err = ResError ();
  221.         if (strHandle == nil) {
  222.         #if DEBUG
  223.             SysDebugStr ("\p!!strHandle is nil!!");
  224.         #endif
  225.         }
  226.  
  227.         if (err != noErr) {
  228.         #if DEBUG
  229.             SysDebugStr ("\p!!Error from Get1Resource('STR#', 128)!!");
  230.         #endif
  231.         }
  232.  
  233.         if (strHandle != nil) {
  234.             gInputSourceNames = NewHandleSys (GetHandleSize (strHandle));
  235.             BlockMoveData (*strHandle, *gInputSourceNames, GetHandleSize (strHandle));
  236.             ReleaseResource (strHandle);
  237.         } else if (err == noErr) {
  238.             err = resNotFound;
  239.         #if DEBUG
  240.             SysDebugStr ("\p!!Error Get1Resource('STR#', 128), resNotFound!!");
  241.         #endif
  242.         }
  243.  
  244.         driverName = GetString (128);
  245.         err = ResError ();
  246.         if (driverName == nil) {
  247.         #if DEBUG
  248.             SysDebugStr ("\p!!driverName is nil!!");
  249.         #endif
  250.         }
  251.  
  252.         if (err != noErr) {
  253.         #if DEBUG
  254.             SysDebugStr ("\p!!Error from GetString(128)!!");
  255.         #endif
  256.         }
  257.  
  258.         if (driverName != nil) {
  259.             gDriverName = (StringHandle)NewHandleSys (GetHandleSize ((Handle)driverName));
  260.             BlockMoveData (*driverName, *gDriverName, GetHandleSize ((Handle)driverName));
  261.             ReleaseResource ((Handle)driverName);
  262.         } else if (err == noErr) {
  263.             err = resNotFound;
  264.         #if DEBUG
  265.             SysDebugStr ("\p!!Error GetString(128), resNotFound!!");
  266.         #endif
  267.         }
  268.  
  269.         CloseResFile (resRefNum);
  270.     }
  271.  
  272.     if (err == noErr) {
  273.         //make an alias to ourselves so that we can open our driver later if needed
  274.         err = NewAlias (nil, initInfo->fragLocator.u.onDisk.fileSpec, &gAliasToDriver);
  275.     }
  276.  
  277. #if DEBUG
  278.     if (err != noErr) {
  279.         SysDebugStr ("\p!!Error in FragInit!!");
  280.     }
  281. #endif
  282.  
  283.     return (err);
  284. }
  285.  
  286. pascal void FragTerm (void) {
  287.     if (gDrvrIcon != nil) {
  288.         DisposeHandle (gDrvrIcon);
  289.         gDrvrIcon = nil;
  290.     }
  291.  
  292.     if (gInputSourceNames != nil) {
  293.         DisposeHandle (gInputSourceNames);
  294.         gInputSourceNames = nil;
  295.     }
  296.  
  297.     if (gAliasToDriver != nil) {
  298.         DisposeHandle ((Handle)gAliasToDriver);
  299.         gAliasToDriver = nil;
  300.     }
  301. }
  302.  
  303. //----------------------------------------------------------------------------------
  304. //                                    Driver calls
  305. //----------------------------------------------------------------------------------
  306.  
  307. /*
  308.     Always run at task level, can allocate and move memory.
  309. */
  310. static OSStatus DriverInitializeCmd (AddressSpaceID addressSpaceID, DriverInitInfoPtr initialInfo) {
  311. #pragma unused (addressSpaceID, initialInfo)
  312.     OSStatus            err = noErr;
  313.  
  314. #if DEBUG
  315.     SysDebugStr ("\pin DriverInitializeCmd;g");
  316. #endif
  317.  
  318.     gDrvrRefNum = initialInfo->refNum;
  319.  
  320. #if DEBUG
  321.     if (err != noErr) {
  322.         SysDebugStr ("\p!!Error in DriverInitializeCmd!!");
  323.     }
  324. #if FULLDEBUG
  325.     SysDebugStr ("\pleaving DriverInitializeCmd;g");
  326. #endif
  327. #endif
  328.  
  329.     return (err);
  330. }
  331.  
  332. /*
  333.     Always run at task level, can allocate and move memory.
  334. */
  335. static OSStatus DriverFinalizeCmd (DriverFinalInfoPtr finalInfo) {
  336. #pragma unused (finalInfo)
  337.     OSStatus            err = noErr;
  338.  
  339. #if DEBUG
  340.     SysDebugStr ("\pin DriverFinalizeCmd;g");
  341. #endif
  342.  
  343. #if DEBUG
  344.     if (err != noErr) {
  345.         SysDebugStr ("\p!!Error in DriverFinalizeCmd!!");
  346.     }
  347. #if FULLDEBUG
  348.     SysDebugStr ("\pleaving DriverFinalizeCmd;g");
  349. #endif
  350. #endif
  351.  
  352.     return (err);
  353. }
  354.  
  355. /*
  356.     Always run at task level, can allocate and move memory.
  357. */
  358. static OSStatus DriverSupersededCmd (DriverSupersededInfoPtr supersededInfo) {
  359. #pragma unused (supersededInfo)
  360.  
  361.     OSErr            err = noErr;
  362.  
  363. #if DEBUG
  364.     SysDebugStr ("\pin DriverSupersededCmd;g");
  365. #endif
  366.  
  367. #if DEBUG
  368.     if (err != noErr) {
  369.         SysDebugStr ("\p!!Error in DriverSupersededCmd!!");
  370.     }
  371. #if FULLDEBUG
  372.     SysDebugStr ("\pleaving DriverSupersededCmd;g");
  373. #endif
  374. #endif
  375.  
  376.     return (err);
  377. }
  378.  
  379. /*
  380.     Always run at task level, can allocate and move memory.
  381. */
  382. static OSStatus DriverReplaceCmd (AddressSpaceID addressSpaceID, DriverReplaceInfoPtr replaceInfo) {
  383. #pragma unused (addressSpaceID, replaceInfo)
  384.     OSStatus            err = noErr;
  385.  
  386. #if DEBUG
  387.     SysDebugStr ("\pin DriverReplaceCmd;g");
  388. #endif
  389.  
  390. #if DEBUG
  391.     if (err != noErr) {
  392.         SysDebugStr ("\p!!Error in DriverReplaceCmd!!");
  393.     }
  394. #if FULLDEBUG
  395.     SysDebugStr ("\pleaving DriverReplaceCmd;g");
  396. #endif
  397. #endif
  398.  
  399.     return (err);
  400. }
  401.  
  402. /*
  403.     Always run at task level, can allocate and move memory.
  404. */
  405. static OSStatus DriverOpenCmd (AddressSpaceID addressSpaceID, ParmBlkPtr pb) {
  406. #pragma unused (addressSpaceID, pb)
  407.     OSStatus            err = noErr;
  408.  
  409. #if DEBUG
  410.     SysDebugStr ("\pin DriverOpenCmd;g");
  411. #endif
  412.  
  413.     gSoundBuffer = NewPtrSys (kSamplesInBuffer * 4);    //room for 16 bit stereo samples
  414.  
  415.     if (gSoundBuffer != nil) {
  416.         gSimulatedHWIntProc = NewTimerProc (HWIntProc);
  417.         SetHardwareToDefault ();
  418.  
  419.         err = SPBSignInDevice (gDrvrRefNum, *gDriverName);
  420.     } else {
  421.     #if DEBUG
  422.         SysDebugStr ("\p!!couldn't allocate memory for our buffer!!");
  423.     #endif
  424.         err = MemError ();
  425.     }
  426.  
  427. #if DEBUG
  428.     if (err != noErr) {
  429.         SysDebugStr ("\p!!Error in DriverOpenCmd!!");
  430.     }
  431. #if FULLDEBUG
  432.     SysDebugStr ("\pleaving DriverOpenCmd;g");
  433. #endif
  434. #endif
  435.  
  436.     return (err);
  437. }
  438.  
  439. /*
  440.     Always run at task level, can allocate and move memory.
  441. */
  442. static OSStatus DriverCloseCmd (ParmBlkPtr pb) {
  443. #pragma unused (pb)
  444.     OSStatus            err = noErr;
  445.  
  446. #if DEBUG
  447.     SysDebugStr ("\pin DriverCloseCmd;g");
  448. #endif
  449.  
  450.     (void)SPBSignOutDevice (gDrvrRefNum);
  451.     DisposePtr (gSoundBuffer);
  452.     gSoundBuffer = nil;
  453.     DisposeRoutineDescriptor (gSimulatedHWIntProc);
  454.     gSimulatedHWIntProc = nil;
  455.  
  456. #if FULLDEBUG
  457.     SysDebugStr ("\pleaving DriverCloseCmd;g");
  458. #endif
  459.  
  460.     return (err);
  461. }
  462.  
  463. /*
  464.     May run at interrupt level, CANNOT allocate or move memory.
  465. */
  466. static OSStatus DriverControlCmd (AddressSpaceID addressSpaceID, IOCommandID ioCommandID, IOCommandKind ioCommandKind, SoundParamPtr pb) {
  467. #pragma unused (addressSpaceID, ioCommandID, ioCommandKind)
  468.     OSStatus            err            = noErr;
  469.     OSType                selector    = 0;
  470.  
  471. #if FULLDEBUG
  472.     SysDebugStr ("\pin DriverControlCmd;g");
  473. #endif
  474.  
  475.     if (pb->csCode == 2) {
  476.         selector = ((OSType*)pb->csParam)[0];
  477.     }
  478.  
  479.     switch (selector) {
  480.         //Control calls that are required to be supported
  481.         case siCompressionType:
  482.             //Set the compression type. Some devices allow the incoming samples to be
  483.             //compressed before being placed in your application’s input buffer. The
  484.             //infoData parameter points to a buffer of type OSType, which is the
  485.             //compression type.
  486.         #if DEBUG2
  487.             SysDebugStr ("\pcontrol: siCompressionType");
  488.         #endif
  489.             if (((OSType*)pb->csParam)[1] != 'NONE') {
  490.                 err = siInvalidCompression;    //we don't support compression
  491.             }
  492.             break;
  493.         case siContinuous:
  494.             //Set the state of continuous recording from this device. If recording
  495.             //is being turned off, the driver stops recording samples to its internal buffer.
  496.             //Only sound input device drivers that support asynchronous recording support
  497.             //continuous recording. The infoData parameter points to an integer, which is
  498.             //the state of continuous recording (0 is off, 1 is on).
  499.         #if DEBUG2
  500.             SysDebugStr ("\pcontrol: siContinuous");
  501.         #endif
  502.             if (((SInt16*)pb->csParam)[2] == 0 || ((SInt16*)pb->csParam)[2] == 1) {
  503.                 gContinuousOn = ((SInt16*)pb->csParam)[2];
  504.             } else {
  505.                 err = paramErr;
  506.             }
  507.             break;
  508.         case siLevelMeterOnOff:
  509.             //Set the current state of the level meter. For calls to set the level meter,
  510.             //the infoData parameter points to an integer that indicates whether the level meter
  511.             //is off (0) or on (1).
  512.         #if DEBUG2
  513.             SysDebugStr ("\pcontrol: siLevelMeterOnOff");
  514.         #endif
  515.             if (((SInt16*)pb->csParam)[2] == 0 || ((SInt16*)pb->csParam)[2] == 1) {
  516.                 gLevelMeterOn = ((SInt16*)pb->csParam)[2];
  517.             } else {
  518.                 err = paramErr;
  519.             }
  520.             break;
  521.         case siNumberChannels:
  522.             //Set the number of channels this device is to record. The infoData parameter points
  523.             //to an integer, which indicates the number of channels. Note that this selector
  524.             //determines the format of the data stream output by the driver. If the number of
  525.             //channels is 1, the driver should output monophonic data in response to a Read call.
  526.             //If the number of channels is 2, the driver should output interleaved stereo data.
  527.         #if DEBUG2
  528.             SysDebugStr ("\pcontrol: siNumberChannels");
  529.         #endif
  530.             if (((SInt16*)pb->csParam)[2] >= 1 && ((SInt16*)pb->csParam)[2] <= 2) {
  531.                 gNumberChannels = ((SInt16*)pb->csParam)[2];
  532.             } else {
  533.                 err = notEnoughHardwareErr;
  534.             }
  535.             break;
  536.         case siRecordingQuality:
  537.             //Set the current quality of recorded sound. The infoData parameter points to a buffer
  538.             //of type OSType, which is the recording quality. Currently foud qualities are supported,
  539.             //defined by these constants:
  540.             //            siCDQuality                            = 'cd  ',                /*44.1kHz, stereo, 16 bit*/
  541.             //            siBestQuality                        = 'best';                /*22kHz, mono, 8 bit*/
  542.             //            siBetterQuality                        = 'betr';                /*22kHz, mono, MACE 3:1*/
  543.             //            siGoodQuality                        = 'good';
  544.             //These qualities are defined by the sound input device driver. Usually best means
  545.             //monaural, 8-bit, 22 kHz, sound with no compression.
  546.         #if DEBUG2
  547.             SysDebugStr ("\pcontrol: siRecordingQuality");
  548.         #endif
  549.             switch (((OSType*)pb->csParam)[1]) {
  550.                 case siCDQuality:
  551.                     gRecordingQuality = siCDQuality;
  552.                     gSampleRate = rate44khz;
  553.                     gSampleSize = 16;
  554.                     gNumberChannels = 2;
  555.                     gCompressionType = 'NONE';
  556.                     break;
  557.                 case siBestQuality:
  558.                     gRecordingQuality = siBestQuality;
  559.                     gSampleRate = rate22050hz;
  560.                     gSampleSize = 8;
  561.                     gNumberChannels = 1;
  562.                     gCompressionType = 'NONE';
  563.                     break;
  564.                 case siBetterQuality:
  565.                     gRecordingQuality = siBetterQuality;
  566.                     gSampleRate = rate22050hz;
  567.                     gSampleSize = 8;
  568.                     gNumberChannels = 1;
  569.                     gCompressionType = 'NONE';
  570.                     break;
  571.                 case siGoodQuality:
  572.                     gRecordingQuality = siGoodQuality;
  573.                     gSampleRate = rate11025hz;
  574.                     gSampleSize = 8;
  575.                     gNumberChannels = 1;
  576.                     gCompressionType = 'NONE';
  577.                     break;
  578.                 default:
  579.                     err = siUnknownQuality;
  580.             }
  581.             break;
  582.         case siSampleRate:
  583.             //Set the sample rate to be produced by this device. The sample rate must be in the
  584.             //range 0 to 65535.65535 Hz. The sample rate is declared as a Fixed data type. In
  585.             //order to accommodate sample rates greater than 32 kHz, the most significant bit is
  586.             //not treated as a sign bit; instead, that bit is interpreted as having the value 32,768.
  587.             //The infoData parameter points to a buffer of type Fixed, which is the sample rate.
  588.         #if DEBUG2
  589.             SysDebugStr ("\pcontrol: siSampleRate");
  590.         #endif
  591.             if (((UnsignedFixed*)pb->csParam)[1] == rate44khz || ((UnsignedFixed*)pb->csParam)[1] == rate22050hz || ((UnsignedFixed*)pb->csParam)[1] == rate11025hz) {
  592.                 gSampleRate = ((UnsignedFixed*)pb->csParam)[1];
  593.             } else {
  594.                 err = siInvalidSampleRate;
  595.             }
  596.             break;
  597.         case siSampleSize:
  598.             //Set the sample size to be produced by this device. Because some compression formats
  599.             //require specific sample sizes, this selector might return an error when compression
  600.             //is used. The infoData parameter points to an integer, which is the sample size.
  601.         #if DEBUG2
  602.             SysDebugStr ("\pcontrol: siSampleSize");
  603.         #endif
  604.             if (((SInt16*)pb->csParam)[2] == 8 || ((SInt16*)pb->csParam)[2] == 16) {
  605.                 gSampleSize = ((SInt16*)pb->csParam)[2];
  606.             } else {
  607.                 err = siInvalidSampleSize;
  608.             }
  609.             break;
  610.         case siTwosComplementOnOff:
  611.             //Set the current state of the two’s complement feature. This selector only applies to
  612.             //8-bit data. (16-bit samples are always stored in two’s complement format.) If on, the
  613.             //driver stores all samples in the application buffer as two’s complement values
  614.             //(that is, –128 to 127). Otherwise, the driver stores the samples as offset binary
  615.             //values (that is, 0 to 255). The infoData parameter points to an integer, which is the
  616.             //current state of the two’s complement feature (1 if two’s complement output is desired,
  617.             //0 otherwise).
  618.         #if DEBUG2
  619.             SysDebugStr ("\pcontrol: siTwosComplementOnOff");
  620.         #endif
  621.             if (((SInt16*)pb->csParam)[2] == 0 || ((SInt16*)pb->csParam)[2] == 1) {
  622.                 gTwosComplementOn = ((SInt16*)pb->csParam)[2];
  623.             } else {
  624.                 err = paramErr;
  625.             }
  626.             break;
  627.  
  628.         //Sound Manager only calls
  629.         case siCloseDriver:
  630.             //The Sound Input Manager sends this selector when it closes a device previously
  631.             //opened with write permission. The sound input device driver should stop any
  632.             //recording in progress, deallocate the input hardware, and initialize local
  633.             //variables to default settings.
  634.         #if DEBUG2
  635.             SysDebugStr ("\pcontrol: siCloseDriver");
  636.         #endif
  637.             //We will actually stop the hardware at the next hardware interrupt
  638.             gStopRecording = true;
  639.             break;
  640.         case siInitializeDriver:
  641.             //The Sound Input Manager sends this selector when it opens a sound input device
  642.             //with write permission. The sound input device driver initializes local variables
  643.             //and prepares to start recording. If possible, the driver initializes the device
  644.             //to a sampling rate of 22 kHz, a sample size of 8 bits, mono recording, no compression,
  645.             //automatic gain control on, and all other features off.
  646.         #if DEBUG2
  647.             SysDebugStr ("\pcontrol: siInitializeDriver");
  648.         #endif
  649.             SetHardwareToDefault ();
  650.             break;
  651.         case siPauseRecording:
  652.             //The Sound Input Manager uses this selector to set the current pause state.
  653.             //The sound input device driver continues recording but does not store the sampled
  654.             //data in a buffer. The infoData parameter points to an integer, which indicates
  655.             //the state of pausing (0 is off, 1 is on).
  656.         #if DEBUG2
  657.             SysDebugStr ("\pcontrol: siPauseRecording");
  658.         #endif
  659.             gPauseState = ((SInt16*)pb->csParam)[2];
  660.             break;
  661.         case siUserInterruptProc:
  662.             //The Sound Input Manager sends this selector to specify the sound input interrupt
  663.             //routine that the sound input device driver should call. The infoData parameter
  664.             //points to a procedure pointer, which is the address of the sound input interrupt routine.
  665.         #if DEBUG2
  666.             SysDebugStr ("\pcontrol: siUserInterruptProc");
  667.         #endif
  668.             gUserInterruptProc = ((SIInterruptUPP*)pb->csParam)[1];
  669.             break;
  670.  
  671.         //Control calls that can be optionally supported
  672.         case siActiveChannels:
  673.             //Set the channels to record from. When setting the active channels, the data passed
  674.             //in is a long integer that is interpreted as a bitmap describing the channels to record
  675.             //from. For example, if bit 0 is set, then the first channel is made active. The samples
  676.             //for each active channel are interleaved in the application’s buffer.
  677.         #if DEBUG2
  678.             SysDebugStr ("\pcontrol: siActiveChannels");
  679.         #endif
  680.             if (((SInt32*)pb->csParam)[1] >= 0x01 && ((SInt32*)pb->csParam)[1] <= 0x03) {
  681.                 gActiveChannels = ((SInt32*)pb->csParam)[1];
  682.             } else {
  683.                 err = notEnoughHardwareErr;
  684.             }
  685.             break;
  686.         case siAGCOnOff:
  687.             //Set the current state of the automatic gain control feature. The infoData parameter
  688.             //points to an integer, which is 0 if gain control is off and 1 if it is on.
  689.         #if DEBUG2
  690.             SysDebugStr ("\pcontrol: siAGCOnOff");
  691.         #endif
  692.             if (((SInt16*)pb->csParam)[2] == 0 || ((SInt16*)pb->csParam)[2] == 1) {
  693.                 gAGCOn = ((SInt16*)pb->csParam)[2];
  694.             } else {
  695.                 err = paramErr;
  696.             }
  697.             break;
  698.         case siInputGain:
  699.             //Set the current sound input gain. If the available hardware allows adjustment of the
  700.             //recording gain, this selector lets you get and set the gain. In response to a Control
  701.             //call, a sound input driver sets the gain level used for all subsequent recording to the
  702.             //specified value. The infoData parameter points to a 4-byte value of type Fixed ranging
  703.             //from 0.5 to 1.5, where 1.5 specifies maximum gain.
  704.         #if DEBUG2
  705.             SysDebugStr ("\pcontrol: siInputGain");
  706.         #endif
  707.             if (((Fixed*)pb->csParam)[1] >= (Fixed)0.5 && ((Fixed*)pb->csParam)[1] <= (Fixed)1.5) {
  708.                 gInputGain = ((Fixed*)pb->csParam)[1];
  709.             } else {
  710.                 err = paramErr;
  711.             }
  712.             break;
  713.         case siInputSource:
  714.             //Set the current sound input source. If the available hardware allows recording from more
  715.             //than one source, this selector lets you get and set the source. In response to a Control
  716.             //call, a sound input driver sets the source of all subsequent recording to the value passed
  717.             //in. If the value is less than 1 or greater than the number of input sources, the driver
  718.             //returns paramErr; if the driver supports only one source, it returns siUnknownInfoType. The
  719.             //infoData parameter points to an integer, which is the index of the current sound input source.
  720.         #if DEBUG2
  721.             SysDebugStr ("\pcontrol: siInputSource");
  722.         #endif
  723.             if (((SInt16*)pb->csParam)[2] >= 1 && ((SInt16*)pb->csParam)[2] <= 3) {
  724.                 gCurrentInputSource = ((SInt16*)pb->csParam)[2];
  725.             } else {
  726.                 err = notEnoughHardwareErr;
  727.             }
  728.             break;
  729.         case siOptionsDialog:
  730.             //Cause the driver to display the Options dialog box (SPBSetDeviceInfo). This dialog box
  731.             //is designed to allow the user to configure device-specific features of the sound input
  732.             //hardware. With SPBSetDeviceInfo, the infoData parameter is unused.
  733.         #if DEBUG2
  734.             SysDebugStr ("\pcontrol: siOptionsDialog");
  735.         #endif
  736.             err = DoOptionsDialog ();
  737.             break;
  738.         case siPlayThruOnOff:
  739.             //Set the current play-through state and volume. The infoData parameter points to an integer,
  740.             //which indicates the current play-through volume (1 to 7). If that integer is 0, then
  741.             //play-through is off.
  742.         #if DEBUG2
  743.             SysDebugStr ("\pcontrol: siPlayThruOnOff");
  744.         #endif
  745.             err = notEnoughHardwareErr;
  746.             //    If our (fake) hardware actually did playthrough, this would be useful...
  747.         /*
  748.             if (((short*)pb->csParam)[2] >= 0 || ((short*)pb->csParam)[2] <= 7) {
  749.                 gPlayThruVolume = ((short*)pb->csParam)[2];
  750.             } else {
  751.                 err = notEnoughHardwareErr;
  752.             }
  753.         */
  754.             break;
  755.         case siStereoInputGain:
  756.             //Set the current stereo sound input gain. If the available hardware allows adjustment of
  757.             //the recording gain, this selector lets you get and set the gain for each of two channels
  758.             //(left or right). In response to a Status call, a sound input driver should return the
  759.             //current gain setting for the specified channel. In response to a Control call, a sound input
  760.             //driver should set the gain level used for all subsequent recording to the specified value.
  761.             //The infoData parameter points to two 4-byte values of type Fixed ranging from 0.5 to 1.5,
  762.             //where 1.5 specifies maximum gain. The first of these values is equivalent to the gain for
  763.             //the left channel and the second value is equivalent to the gain for the right channel.
  764.         #if DEBUG2
  765.             SysDebugStr ("\pcontrol: siStereoInputGain");
  766.         #endif
  767.             if (((Fixed*)pb->csParam)[1] <= 1.5 && ((Fixed*)pb->csParam)[1] >= 0.5 && ((Fixed*)pb->csParam)[2] <= 1.5 && ((Fixed*)pb->csParam)[2] >= 0.5) {
  768.                 gLeftInputGain = ((Fixed*)pb->csParam)[1];
  769.                 gRightInputGain = ((Fixed*)pb->csParam)[2];
  770.             } else {
  771.                 err = paramErr;
  772.             }
  773.             break;
  774.         case siVoxRecordInfo:
  775.             //Set the current VOX recording parameters. The infoData parameter points to two integers.
  776.             //The first integer indicates whether VOX recording is on or off (0 if off, 1 if on). The
  777.             //second integer indicates the VOX record trigger value. Trigger values range from 0 to 255
  778.             //(0 is trigger immediately, 255 is trigger only on full volume).
  779.         #if DEBUG2
  780.             SysDebugStr ("\pcontrol: siVoxRecordInfo");
  781.         #endif
  782.             if (((SInt16*)pb->csParam)[2] == 0 || ((SInt16*)pb->csParam)[2] == 1) {
  783.                 gVoxRecordingOn = ((SInt16*)pb->csParam)[2];
  784.             } else {
  785.                 err = paramErr;
  786.             }
  787.  
  788.             if (gVoxRecordingOn == 1 && (((SInt16*)pb->csParam)[3] <= 255 && ((SInt16*)pb->csParam)[3] >= 0)) {
  789.                 gVOXStartTrigger = ((SInt16*)pb->csParam)[3];
  790.             } else {
  791.                 err = paramErr;
  792.             }
  793.             break;
  794.         case siVoxStopInfo:
  795.             //Set the current VOX stopping parameters. The infoData parameter points to three integers.
  796.             //The first integer indicates whether VOX stopping is on or off (0 if off, 1 if on). The
  797.             //second integer indicates the VOX stop trigger value. Trigger values range from 0 to 255
  798.             //(255 is stop immediately, 0 is stop only on total silence). The third integer indicates
  799.             //how many milliseconds the trigger value must be continuously valid for recording to be stopped.
  800.             //Delay values range from 0 to 65,535.
  801.         #if DEBUG2
  802.             SysDebugStr ("\pcontrol: siVoxStopInfo");
  803.         #endif
  804.             if (((SInt16*)pb->csParam)[2] == 0 || ((SInt16*)pb->csParam)[2] == 1) {
  805.                 gVoxStoppingOn = ((SInt16*)pb->csParam)[2];
  806.             } else {
  807.                 err = paramErr;
  808.             }
  809.  
  810.             if (gVoxStoppingOn == 1 && (((SInt16*)pb->csParam)[3] <= 255 && ((SInt16*)pb->csParam)[3] >= 0)) {
  811.                 gVOXStopTrigger = ((SInt16*)pb->csParam)[3];
  812.                 gVOXDelay = ((SInt16*)pb->csParam)[4];
  813.             } else {
  814.                 err = paramErr;
  815.             }
  816.             break;
  817.  
  818.         //Unknown or unsupported control call
  819.         default:
  820.         #if DEBUG
  821.             SysDebugStr ("\pcontrol: unknown selector");
  822.         #endif
  823.             err = controlErr;
  824.     }
  825.  
  826. #if DEBUG
  827.     if (err != noErr && err != controlErr) {
  828.         SysDebugStr ("\p!!Error in DriverControlCmd!!");
  829.     }
  830. #if FULLDEBUG
  831.     SysDebugStr ("\pleaving DriverControlCmd;g");
  832. #endif
  833. #endif
  834.  
  835.     return (err);
  836. }
  837.  
  838. /*
  839.     May run at interrupt level, CANNOT allocate or move memory.
  840. */
  841. static OSStatus DriverStatusCmd (AddressSpaceID addressSpaceID, IOCommandID ioCommandID, IOCommandKind ioCommandKind, SoundParamPtr pb) {
  842. #pragma unused (addressSpaceID, ioCommandID, ioCommandKind)
  843.     OSStatus            err            = noErr;
  844.     OSType                selector    = 0;
  845.     Handle                iconHandle,
  846.                         compressionAvailable,
  847.                         sampleRateAvailable,
  848.                         sampleSizeAvailable;
  849.     SoundInfoList        info;
  850.  
  851. #if FULLDEBUG
  852.     SysDebugStr ("\pin DriverStatusCmd;g");
  853. #endif
  854.  
  855.     if (pb->csCode == 2) {
  856.         selector = ((OSType*)pb->csParam)[0];
  857.     }
  858.  
  859.     switch (selector) {
  860.         //Status calls that are required to be supported
  861.         case siAsync:
  862.             //Determine whether the driver supports asynchronous recording functions. The infoData parameter
  863.             //points to an integer, which is 0 if the driver supports synchronous calls only and 1 otherwise.
  864.             //Some sound input drivers do not support asynchronous recording at all, and some might support
  865.             //asynchronous recording only on certain hardware configurations.
  866.         #if DEBUG2
  867.             SysDebugStr ("\pstatus: siAsync");
  868.         #endif
  869.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  870.             ((SInt16*)pb->csParam)[2] = 1;    //we can do async recording
  871.             break;
  872.         case siChannelAvailable:
  873.             //Get the maximum number of channels this device can record. The infoData parameter points to an
  874.             //integer, which is the number of available channels.
  875.         #if DEBUG2
  876.             SysDebugStr ("\pstatus: siChannelAvailable");
  877.         #endif
  878.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  879.             ((SInt16*)pb->csParam)[2] = 2;    //we can do stereo (note: Sound Manager doesn't currently work with more than 2 channels)
  880.             break;
  881.         case siCompressionAvailable:
  882.             //Get the number and list of compression types this device can produce. The infoData parameter
  883.             //points to an integer, which is the number of compression types, followed by a handle. The
  884.             //handle references a list of compression types, each of type OSType.
  885.         #if DEBUG2
  886.             SysDebugStr ("\pstatus: siCompressionAvailable");
  887.         #endif
  888.             compressionAvailable = NewHandle (sizeof (OSType) * kNumCompressions);
  889.             if (compressionAvailable != nil) {
  890.                 ((OSType*)*compressionAvailable)[0] = 'NONE';
  891.                 info.count = kNumCompressions;
  892.                 info.infoHandle = compressionAvailable;
  893.                 ((SInt32*)pb->csParam)[0] = sizeof (SoundInfoList);        //number of bytes being returned
  894.                 *(SoundInfoList*)(pb->csParam+2) = info;
  895.             }
  896.             break;
  897.         case siCompressionFactor:
  898.             //Get the compression factor of the current compression type. For example, the compression factor
  899.             //for MACE 3:1 compression is 3. If a sound input device driver supports only compression type 'NONE',
  900.             //the returned compression type is 1. The infoData parameter points to an integer, which is the
  901.             //compression factor.
  902.         #if DEBUG2
  903.             SysDebugStr ("\pstatus: siCompressionFactor");
  904.         #endif
  905.             if (gCompressionType == 'NONE') {
  906.                 ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  907.                 ((SInt16*)pb->csParam)[2] = 1;    //no compression equals 1:1
  908.             }
  909.             break;
  910.         case siCompressionType:
  911.             //Get the compression type. Some devices allow the incoming samples to be compressed before being
  912.             //placed in your application’s input buffer. The infoData parameter points to a buffer of type
  913.             //OSType, which is the compression type.
  914.         #if DEBUG2
  915.             SysDebugStr ("\pstatus: siCompressionType");
  916.         #endif
  917.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  918.             ((OSType*)pb->csParam)[1] = gCompressionType;
  919.             break;
  920.         case siContinuous:
  921.             //Get the state of continuous recording from this device. If recording is being turned off, the
  922.             //driver stops recording samples to its internal buffer. Only sound input device drivers that
  923.             //support asynchronous recording support continuous recording. The infoData parameter points to an
  924.             //integer, which is the state of continuous recording (0 is off, 1 is on).
  925.         #if DEBUG2
  926.             SysDebugStr ("\pstatus: siContinuous");
  927.         #endif
  928.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  929.             ((SInt16*)pb->csParam)[2] = gContinuousOn;
  930.             break;
  931.         case siDeviceBufferInfo:
  932.             //Get the size of the device’s internal buffer. This information can be useful when you want to
  933.             //modify sound input data at interrupt time. Note, however, that if a driver is recording continuously,
  934.             //then the size of the buffer passed to your sound input interrupt routine might be greater than the
  935.             //size this selector returns because data recorded between calls to SPBRecord as well as recorded
  936.             //during calls to SPBRecord will be sent to your interrupt routine. The infoData parameter points to
  937.             //a long integer, which is the size of the device’s internal buffer.
  938.         #if DEBUG2
  939.             SysDebugStr ("\pstatus: siDeviceBufferInfo");
  940.         #endif
  941.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  942.             ((SInt32*)pb->csParam)[1] = kSamplesInBuffer * gNumberChannels * (gSampleSize / 8);
  943.             break;
  944.         case siDeviceConnected:
  945.             //Get the state of the device connection. The infoData parameter points to an integer, which is one
  946.             //of the following constants:
  947.             //            siDeviceIsConnected                    = 1;
  948.             //            siDeviceNotConnected                = 0;
  949.             //            siDontKnowIfConnected                = -1;
  950.             //The siDeviceIsConnected constant indicates that the device is connected and ready. The
  951.             //siDeviceNotConnected constant indicates that the device is not connected. The siDontKnowIfConnected
  952.             //constant indicates that the Sound Input Manager cannot determine whether the device is connected.
  953.         #if DEBUG2
  954.             SysDebugStr ("\pstatus: siDeviceConnected");
  955.         #endif
  956.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  957.             ((SInt16*)pb->csParam)[2] = siDeviceIsConnected;
  958.             break;
  959.         case siDeviceIcon:
  960.             //Get the device’s icon and icon mask. In response to a Status call, a sound input device driver
  961.             //should return, in the location specified by the infoData parameter, a handle to a block of memory
  962.             //that contains the icon and its mask in the format of an 'ICN#' resource. It is the driver’s
  963.             //responsibility to allocate that block of memory, but it should not releasee it. The software issuing
  964.             //this selector is responsible for disposing of the handle. As a result, a device driver should detach
  965.             //any resource handles (by calling DetachResource) before returning them to the caller.
  966.         #if DEBUG2
  967.             SysDebugStr ("\pstatus: siDeviceIcon");
  968.         #endif
  969.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  970.             iconHandle = gDrvrIcon;
  971.             err = HandToHand (&iconHandle);
  972.             if (err != noErr) {
  973.                 SysDebugStr ("\pHandToHand returned an error");
  974.             }
  975.             ((Handle*)pb->csParam)[1] = iconHandle;
  976.             break;
  977.         case siDeviceName:
  978.             //Get the name of the sound input device. Your application must pass a pointer to a buffer that will
  979.             //be filled in with the device’s name. The buffer needs to be large enough to hold a Str255 data type.
  980.         #if DEBUG2
  981.             SysDebugStr ("\pstatus: siDeviceName");
  982.         #endif
  983.             ((SInt32*)pb->csParam)[0] = 0;    //Sound Manager doesn't have to copy any data
  984.             BlockMoveData (gDriverName[0], ((Handle*)pb->csParam)[1], *gDriverName[0]+1);
  985.             break;
  986.         case siLevelMeterOnOff:
  987.             //Get the current state of the level meter. To get the level meter setting, the infoData parameter
  988.             //points to two integers; the first integer indicates the state of the level meter, and the second
  989.             //integer contains the level value of the meter. The level meter setting is an integer that ranges
  990.             //from 0 (no volume) to 255 (full volume). 
  991.         #if DEBUG2
  992.             SysDebugStr ("\pstatus: siLevelMeterOnOff");
  993.         #endif
  994.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  995.             ((SInt16*)pb->csParam)[2] = gLevelMeterOn;
  996.             ((SInt16*)pb->csParam)[3] = 0;
  997.             break;
  998.         case siNumberChannels:
  999.             //Get the number of channels this device is to record. The infoData parameter points to an integer,
  1000.             //which indicates the number of channels. Note that this selector determines the format of the data
  1001.             //stream output by the driver. If the number of channels is 1, the driver should output monophonic data
  1002.             //in response to a Read call. If the number of channels is 2, the driver should output interleaved
  1003.             //stereo data.
  1004.         #if DEBUG2
  1005.             SysDebugStr ("\pstatus: siNumberChannels");
  1006.         #endif
  1007.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  1008.             ((SInt16*)pb->csParam)[2] = gNumberChannels;
  1009.             break;
  1010.         case siRecordingQuality:
  1011.             //Get the current quality of recorded sound. The infoData parameter points to a buffer of type
  1012.             //OSType, which is the recording quality. Currently four qualities are supported, defined by
  1013.             //these constants:
  1014.             //            siCDQuality                            = 'cd  ',                /*44.1kHz, stereo, 16 bit*/
  1015.             //            siBestQuality                        = 'best';                /*22kHz, mono, 8 bit*/
  1016.             //            siBetterQuality                        = 'betr';                /*22kHz, mono, MACE 3:1*/
  1017.             //            siGoodQuality                        = 'good';
  1018.             //These qualities are defined by the sound input device driver. Usually best means monaural,
  1019.             //8-bit, 22 kHz, sound with no compression.
  1020.         #if DEBUG2
  1021.             SysDebugStr ("\pstatus: siRecordingQuality");
  1022.         #endif
  1023.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  1024.             ((OSType*)pb->csParam)[1] = gRecordingQuality;
  1025.             break;
  1026.         case siSampleRate:
  1027.             //Get the sample rate to be produced by this device. The sample rate must be in the range 0 to
  1028.             //65535.65535 Hz. The sample rate is declared as a Fixed data type. In order to accommodate sample
  1029.             //rates greater than 32 kHz, the most significant bit is not treated as a sign bit; instead, that
  1030.             //bit is interpreted as having the value 32,768. The infoData parameter points to a buffer of type
  1031.             //Fixed, which is the sample rate.
  1032.         #if DEBUG2
  1033.             SysDebugStr ("\pstatus: siSampleRate");
  1034.         #endif
  1035.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  1036.             ((UnsignedFixed*)pb->csParam)[1] = gSampleRate;
  1037.             break;
  1038.         case siSampleRateAvailable:
  1039.             //Get the range of sample rates this device can produce. The infoData parameter points to an integer,
  1040.             //which is the number of sample rates the device supports, followed by a handle. The handle references
  1041.             //a list of sample rates, each of type Fixed. If the device can record a range of sample rates, the
  1042.             //number of sample rates is set to 0 and the handle contains two rates, the minimum and the maximum
  1043.             //of the range of sample rates. Otherwise, a list is returned that contains the sample rates supported.
  1044.             //In order to accommodate sample rates greater than 32 kHz, the most significant bit is not treated as
  1045.             //a sign bit; instead, that bit is interpreted as having the value 32,768.
  1046.         #if DEBUG2
  1047.             SysDebugStr ("\pstatus: siSampleRateAvailable");
  1048.         #endif
  1049.             sampleRateAvailable = NewHandle (sizeof (UnsignedFixed) * kNumRates);
  1050.             if (sampleRateAvailable != nil) {
  1051.                 ((UnsignedFixed*)*sampleRateAvailable)[0] = rate44khz;
  1052.                 ((UnsignedFixed*)*sampleRateAvailable)[1] = rate22050hz;
  1053.                 ((UnsignedFixed*)*sampleRateAvailable)[2] = rate11025hz;
  1054.                 info.count = kNumRates;
  1055.                 info.infoHandle = sampleRateAvailable;
  1056.                 ((SInt32*)pb->csParam)[0] = sizeof (SoundInfoList);        //number of bytes being returned
  1057.                 *(SoundInfoList*)(pb->csParam+2) = info;
  1058.             }
  1059.             break;
  1060.         case siSampleSize:
  1061.             //Get the sample size to be produced by this device. Because some compression formats require specific
  1062.             //sample sizes, this selector might return an error when compression is used. The infoData parameter
  1063.             //points to an integer, which is the sample size.
  1064.         #if DEBUG2
  1065.             SysDebugStr ("\pstatus: siSampleSize");
  1066.         #endif
  1067.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  1068.             ((SInt16*)pb->csParam)[2] = gSampleSize;
  1069.             break;
  1070.         case siSampleSizeAvailable:
  1071.             //Get the range of sample sizes this device can produce. The infoData parameter points to an integer,
  1072.             //which is the number of sample sizes the device supports, followed by a handle. The handle references
  1073.             //a list of sample sizes, each of type Integer.
  1074.         #if DEBUG2
  1075.             SysDebugStr ("\pstatus: siSampleSizeAvailable");
  1076.         #endif
  1077.             sampleSizeAvailable = NewHandle (sizeof (SInt16) * kNumSizes);
  1078.             if (sampleSizeAvailable != nil) {
  1079.                 ((SInt16*)*sampleSizeAvailable)[0] = 8;
  1080.                 ((SInt16*)*sampleSizeAvailable)[1] = 16;
  1081.                 info.count = kNumSizes;
  1082.                 info.infoHandle = sampleSizeAvailable;
  1083.                 ((SInt32*)pb->csParam)[0] = sizeof (SoundInfoList);        //number of bytes being returned
  1084.                 *(SoundInfoList*)(pb->csParam+2) = info;
  1085.             }
  1086.             break;
  1087.         case siTwosComplementOnOff:
  1088.             //Get the current state of the two’s complement feature. This selector only applies to 8-bit data.
  1089.             //(16-bit samples are always stored in two’s complement format.) If on, the driver stores all samples
  1090.             //in the application buffer as two’s complement values (that is, –128 to 127). Otherwise, the driver
  1091.             //stores the samples as offset binary values (that is, 0 to 255). The infoData parameter points to an
  1092.             //integer, which is the current state of the two’s complement feature (1 if two’s complement output
  1093.             //is desired, 0 otherwise).
  1094.         #if DEBUG2
  1095.             SysDebugStr ("\pstatus: siTwosComplementOnOff");
  1096.         #endif
  1097.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  1098.             ((SInt16*)pb->csParam)[2] = gTwosComplementOn;
  1099.             break;
  1100.  
  1101.         //Sound Manager only call
  1102.         case siPauseRecording:
  1103.             //The Sound Input Manager uses this selector to get the current pause state.
  1104.             //The sound input device driver continues recording but does not store the sampled
  1105.             //data in a buffer. The infoData parameter points to an integer, which indicates
  1106.             //the state of pausing (0 is off, 1 is on).
  1107.         #if DEBUG2
  1108.             SysDebugStr ("\pcontrol: siPauseRecording");
  1109.         #endif
  1110.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  1111.             ((SInt16*)pb->csParam)[2] = gPauseState;
  1112.             break;
  1113.  
  1114.         //Status calls that can be optionally supported
  1115.         case siActiveChannels:
  1116.             //Get the channels to record from. When reading the active channels, the data returned is
  1117.             //a bitmap of the active channels.
  1118.         #if DEBUG2
  1119.             SysDebugStr ("\pstatus: siActiveChannels");
  1120.         #endif
  1121.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  1122.             ((SInt32*)pb->csParam)[1] = gActiveChannels;
  1123.             break;
  1124.         case siActiveLevels:
  1125.             //Get the current signal level for each active channel. The infoData parameter points to an array
  1126.             //of integers, the size of which depends on the number of active channels. You can determine how
  1127.             //many channels are active by calling SPBGetDeviceInfo with the siNumberChannels selector.
  1128.         #if DEBUG2
  1129.             SysDebugStr ("\pstatus: siActiveLevels");
  1130.         #endif
  1131.             if (gNumberChannels == 1) {
  1132.                 ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  1133.                 ((SInt16*)pb->csParam)[2] = 0;
  1134.             } else if (gNumberChannels == 2) {
  1135.                 ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  1136.                 ((SInt16*)pb->csParam)[2] = 0;
  1137.                 ((SInt16*)pb->csParam)[3] = 0;
  1138.             }
  1139.             break;
  1140.         case siAGCOnOff:
  1141.             //Get the current state of the automatic gain control feature. The infoData parameter points to an
  1142.             //integer, which is 0 if gain control is off and 1 if it is on.
  1143.         #if DEBUG2
  1144.             SysDebugStr ("\pstatus: siAGCOnOff");
  1145.         #endif
  1146.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  1147.             ((SInt16*)pb->csParam)[2] = gAGCOn;
  1148.             break;
  1149.         case siCompressionHeader:
  1150.             //Get a compressed sound header for the current recording settings. Your application passes in a
  1151.             //pointer to a compressed sound header and the driver fills it in. Before calling SPBGetDeviceInfo
  1152.             //with this selector, you should set the numFrames field of the compressed sound header to the number
  1153.             //of bytes in the sound. When SPBGetDeviceInfo returns successfully, that field contains the number
  1154.             //of sample frames in the sound. This selector is needed only by drivers that use compression types
  1155.             //that are not directly supported by Apple. If you call this selector after recording a sound, your
  1156.             //application can get enough information about the sound to play it or save it in a file. The infoData
  1157.             //parameter points to a compressed sound header.
  1158.         #if DEBUG2
  1159.             SysDebugStr ("\pstatus: siCompressionHeader");
  1160.         #endif
  1161.             err = siUnknownInfoType;    //we don't support compression
  1162.             break;
  1163.         case siCompressionNames:
  1164.             //Get a list of names of the compression types supported by the sound input device. In response to a
  1165.             //Status call, a sound input device driver returns, in the location specified by the infoData parameter,
  1166.             //a handle to a block of memory that contains the names of all compression types supported by the driver.
  1167.             //It is the driver’s responsibility to allocate that block of memory, but it should not release it. The
  1168.             //software issuing this selector is responsible for disposing of the handle. As a result, a device driver
  1169.             //must detach any resource handles (by calling DetachResource) before returning them to the caller. The
  1170.             //data in the handle has the same format as an 'STR#' resource: a two-byte count of the strings in the
  1171.             //resource, followed by the strings themselves. The strings should occur in the same order as the
  1172.             //compression types returned by the siCompressionAvailable selector. If the driver does not support
  1173.             //compression, it returns siUnknownInfoType. If the driver supports compression but for some reason not
  1174.             //all compression types are currently selectable, it returns a list of all available compression types.
  1175.         #if DEBUG2
  1176.             SysDebugStr ("\pstatus: siCompressionNames");
  1177.         #endif
  1178.             err = siUnknownInfoType;    //we don't support compression
  1179.             break;
  1180.         case siInputGain:
  1181.             //Get the current sound input gain. If the available hardware allows adjustment of the recording gain,
  1182.             //this selector lets you get and set the gain. In response to a Status call, a sound input driver returns
  1183.             //the current gain setting. The infoData parameter points to a 4-byte value of type Fixed ranging from
  1184.             //0.5 to 1.5, where 1.5 specifies maximum gain.
  1185.         #if DEBUG2
  1186.             SysDebugStr ("\pstatus: siInputGain");
  1187.         #endif
  1188.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  1189.             ((Fixed*)pb->csParam)[1] = gInputGain;
  1190.             break;
  1191.         case siInputSource:
  1192.             //Get the current sound input source. If the available hardware allows recording from more than one
  1193.             //source, this selector lets you get and set the source. In response to a Status call, a sound input
  1194.             //driver returns the current source value; if the driver supports only one source, it returns
  1195.             //siUnknownInfoType.
  1196.         #if DEBUG2
  1197.             SysDebugStr ("\pstatus: siInputSource");
  1198.         #endif
  1199.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  1200.             ((SInt16*)pb->csParam)[2] = gCurrentInputSource;
  1201.             break;
  1202.         case siInputSourceNames:
  1203.             //Get a list of the names of all the sound input sources supported by the sound input device. In
  1204.             //response to a Status call, a sound input device driver returns, in the location specified by the
  1205.             //infoData parameter, a handle to a block of memory that contains the names of all sound sources
  1206.             //supported by the driver. It is the driver’s responsibility to allocate that block of memory, but it
  1207.             //should not release it. The software issuing this selector is responsible for disposing of the handle.
  1208.             //As a result, a device driver must detach any resource handles (by calling DetachResource) before
  1209.             //returning them to the caller. The data in the handle has the same format as an 'STR#' resource: a
  1210.             //two-byte count of the strings in the resource, followed by the strings themselves. The strings should
  1211.             //occur in the same order as the input sources returned by the siInputSource selector. If the driver
  1212.             //supports only one source, it returns siUnknownInfoType. If the driver supports more than one source
  1213.             //but for some reason not all of them are currently selectable, it returns a list of all available
  1214.             //input sources.
  1215.         #if DEBUG2
  1216.             SysDebugStr ("\pstatus: siInputSourceNames");
  1217.         #endif
  1218.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  1219.             ((Handle*)pb->csParam)[1] = gInputSourceNames;
  1220.             break;
  1221.         case siOptionsDialog:
  1222.             //Determine whether the driver supports an Options dialog box (SPBGetDeviceInfo). This dialog box is
  1223.             //designed to allow the user to configure device-specific features of the sound input hardware. With
  1224.             //SPBGetDeviceInfo, the infoData parameter points to an integer, which indicates whether the driver
  1225.             //supports an Options dialog box (1 if it supports it, 0 otherwise).
  1226.         #if DEBUG2
  1227.             SysDebugStr ("\pstatus: siOptionsDialog");
  1228.         #endif
  1229.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  1230.             ((SInt16*)pb->csParam)[2] = 1;    //we have a dialog
  1231.             break;
  1232.         case siPlayThruOnOff:
  1233.             //Get the current play-through state and volume. The infoData parameter points to an integer,
  1234.             //which indicates the current play-through volume (1 to 7). If that integer is 0, then
  1235.             //play-through is off.
  1236.         #if DEBUG2
  1237.             SysDebugStr ("\pstatus: siPlayThruOnOff");
  1238.         #endif
  1239.             ((SInt32*)pb->csParam)[0] = 2;    //number of bytes being returned
  1240.             ((SInt16*)pb->csParam)[2] = gPlayThruVolume;
  1241.             break;
  1242.         case siStereoInputGain:
  1243.             //Get the current stereo sound input gain. If the available hardware allows adjustment of the recording
  1244.             //gain, this selector lets you get and set the gain for each of two channels (left or right). In response
  1245.             //to a Status call, a sound input driver should return the current gain setting for the specified channel.
  1246.             //The infoData parameter points to two 4-byte values of type Fixed ranging from 0.5 to 1.5, where 1.5
  1247.             //specifies maximum gain. The first of these values is equivalent to the gain for the left channel and the
  1248.             //second value is equivalent to the gain for the right channel.
  1249.         #if DEBUG2
  1250.             SysDebugStr ("\pstatus: siStereoInputGain");
  1251.         #endif
  1252.             ((SInt32*)pb->csParam)[0] = 8;    //number of bytes being returned
  1253.             ((Fixed*)pb->csParam)[1] = gLeftInputGain;
  1254.             ((Fixed*)pb->csParam)[2] = gRightInputGain;
  1255.             break;
  1256.         case siVoxRecordInfo:
  1257.             //Get the current VOX recording parameters. The infoData parameter points to two integers. The first
  1258.             //integer indicates whether VOX recording is on or off (0 if off, 1 if on). The second integer indicates
  1259.             //the VOX record trigger value. Trigger values range from 0 to 255 (0 is trigger immediately, 255 is
  1260.             //trigger only on full volume).
  1261.         #if DEBUG2
  1262.             SysDebugStr ("\pstatus: siVoxRecordInfo");
  1263.         #endif
  1264.             ((SInt32*)pb->csParam)[0] = 4;    //number of bytes being returned
  1265.             ((SInt16*)pb->csParam)[2] = gVoxRecordingOn;
  1266.             ((SInt16*)pb->csParam)[3] = gVOXStartTrigger;
  1267.             break;
  1268.         case siVoxStopInfo:
  1269.             //Get the current VOX stopping parameters. The infoData parameter points to three integers. The
  1270.             //first integer indicates whether VOX stopping is on or off (0 if off, 1 if on). The second integer
  1271.             //indicates the VOX stop trigger value. Trigger values range from 0 to 255 (255 is stop immediately, 0
  1272.             //is stop only on total silence). The third integer indicates how many milliseconds the trigger value must
  1273.             //be continuously valid for recording to be stopped. Delay values range from 0 to 65,535.
  1274.         #if DEBUG2
  1275.             SysDebugStr ("\pstatus: siVoxStopInfo");
  1276.         #endif
  1277.             ((SInt32*)pb->csParam)[0] = 6;    //number of bytes being returned
  1278.             ((SInt16*)pb->csParam)[2] = gVoxStoppingOn;
  1279.             ((SInt16*)pb->csParam)[3] = gVOXStopTrigger;
  1280.             ((SInt16*)pb->csParam)[4] = gVOXDelay;
  1281.             break;
  1282.  
  1283.         //Unknown or unsupported status call
  1284.         default:
  1285.         #if DEBUG
  1286.             SysDebugStr ("\pstatus: unknown selector");
  1287.         #endif
  1288.             err = statusErr;
  1289.     }
  1290.  
  1291. #if DEBUG
  1292.     if (err != noErr && err != statusErr && err != siUnknownInfoType) {
  1293.         SysDebugStr ("\p!!Error in DriverStatusCmd!!");
  1294.     }
  1295. #if FULLDEBUG
  1296.     SysDebugStr ("\pleaving DriverStatusCmd;g");
  1297. #endif
  1298. #endif
  1299.  
  1300.     return (err);
  1301. }
  1302.  
  1303. /*
  1304.     May run at interrupt level, CANNOT allocate or move memory.
  1305. */
  1306. static OSStatus DriverReadCmd (AddressSpaceID addressSpaceID, IOCommandID ioCommandID, IOCommandKind ioCommandKind, ParmBlkPtr pb) {
  1307. #pragma unused (addressSpaceID, ioCommandID, ioCommandKind)
  1308.     OSStatus            err = noErr;
  1309.     double            samplesInBuffer = kSamplesInBuffer,temp, temp2;
  1310.  
  1311. #if DEBUG
  1312.     SysDebugStr ("\pin DriverReadCmd;g");
  1313. #endif
  1314.  
  1315.     gSimulatedHWInterrupt.theTask.tmAddr = gSimulatedHWIntProc;
  1316.     gSimulatedHWInterrupt.theTask.tmWakeUp = 0;
  1317.     gSimulatedHWInterrupt.pb = pb;
  1318.  
  1319.     temp = ((gSampleRate >> 16) / samplesInBuffer);
  1320.  
  1321.     temp2 = -(1000000.0 / temp);    //calculate time in microseconds
  1322.     gInterruptFreq = temp2;
  1323.  
  1324.     InsXTime ((QElemPtr)&gSimulatedHWInterrupt);
  1325.     PrimeTime ((QElemPtr)&gSimulatedHWInterrupt, gInterruptFreq);    //wait for the time it takes to "record" one buffer
  1326.  
  1327.     err = ioInProgress;
  1328.  
  1329. #if DEBUG
  1330.     if (err != noErr && err != ioInProgress) {
  1331.         SysDebugStr ("\p!!Error in DriverReadCmd!!");
  1332.     }
  1333. #if FULLDEBUG
  1334.     SysDebugStr ("\pleaving DriverReadCmd;g");
  1335. #endif
  1336. #endif
  1337.  
  1338.     return (err);
  1339. }
  1340.  
  1341. /*
  1342.     May run at interrupt level, CANNOT allocate or move memory.
  1343. */
  1344. static OSStatus DriverWriteCmd (AddressSpaceID addressSpaceID, IOCommandID ioCommandID, IOCommandKind ioCommandKind, ParmBlkPtr pb) {
  1345. #pragma unused (addressSpaceID, ioCommandID, ioCommandKind, pb)
  1346.     OSStatus            err;
  1347.  
  1348. #if DEBUG
  1349.     SysDebugStr ("\pin DriverWriteCmd;g");
  1350. #endif
  1351.  
  1352.     //Sound input drivers don't have a write command.
  1353.     err = paramErr;
  1354.  
  1355. #if DEBUG
  1356.     if (err != noErr) {
  1357.         SysDebugStr ("\p!!Error in DriverWriteCmd!!");
  1358.     }
  1359. #if FULLDEBUG
  1360.     SysDebugStr ("\pleaving DriverWriteCmd;g");
  1361. #endif
  1362. #endif
  1363.  
  1364.     return (err);
  1365. }
  1366.  
  1367. /*
  1368.     May run at interrupt level, CANNOT allocate or move memory.
  1369. */
  1370. static OSStatus DriverKillIOCmd (ParmBlkPtr pb) {
  1371. #pragma unused (pb)
  1372.     OSStatus            err = noErr;
  1373.  
  1374. #if DEBUG
  1375.     SysDebugStr ("\pin DriverKillIOCmd");
  1376. #endif
  1377.  
  1378.     gStopRecording = true;    //when our next hardware "interrupt" fires we will stop the "hardware"
  1379.  
  1380. #if DEBUG
  1381.     if (err != noErr) {
  1382.         SysDebugStr ("\p!!Error in DriverKillIOCmd!!");
  1383.     }
  1384. #if FULLDEBUG
  1385.     SysDebugStr ("\pleaving DriverKillIOCmd;g");
  1386. #endif
  1387. #endif
  1388.  
  1389.     return (err);
  1390. }
  1391.  
  1392. /*
  1393.     May run at interrupt level, CANNOT allocate or move memory.
  1394. */
  1395. extern OSErr DoDriverIO(AddressSpaceID addressSpaceID, IOCommandID ioCommandID, IOCommandContents ioCommandContents, IOCommandCode ioCommandCode, IOCommandKind ioCommandKind) {
  1396.     OSStatus        status;
  1397.     OSErr            err        = noErr;
  1398.  
  1399. #if FULLDEBUG
  1400.     SysDebugStr ("\pin DoDriverIO;g");
  1401. #endif
  1402.  
  1403.     /*
  1404.         Note: Initialize, Open, KillIO, Close, and Finalize are either synchronous
  1405.         or immediate. Read, Write, Control, and Status may be immediate,
  1406.         synchronous, or asynchronous.
  1407.     */
  1408.     switch (ioCommandCode) {
  1409.         case kInitializeCommand:        /* Always immediate */
  1410.             status = DriverInitializeCmd (addressSpaceID, ioCommandContents.initialInfo);
  1411.             break;
  1412.         case kFinalizeCommand:            /* Always immediate */
  1413.             status = DriverFinalizeCmd (ioCommandContents.finalInfo);
  1414.             break;
  1415.         case kSupersededCommand:        /* Always immediate */
  1416.             status = DriverSupersededCmd (ioCommandContents.supersededInfo);
  1417.             break;
  1418.         case kReplaceCommand:            /* Always immediate, replace an old driver */
  1419.             status = DriverReplaceCmd (addressSpaceID, ioCommandContents.replaceInfo);
  1420.             break;
  1421.         case kOpenCommand:                /* Always immediate */
  1422.             status = DriverOpenCmd (addressSpaceID, ioCommandContents.pb);
  1423.             break;
  1424.         case kCloseCommand:                /* Always immediate */
  1425.             status = DriverCloseCmd (ioCommandContents.pb);
  1426.             break;
  1427.         case kControlCommand:
  1428.             status = DriverControlCmd (addressSpaceID, ioCommandID, ioCommandKind, (SoundParamPtr) ioCommandContents.pb);
  1429.             break;
  1430.         case kStatusCommand:
  1431.             status = DriverStatusCmd (addressSpaceID, ioCommandID, ioCommandKind, (SoundParamPtr) ioCommandContents.pb);
  1432.             break;
  1433.         case kReadCommand:
  1434.             status = DriverReadCmd (addressSpaceID, ioCommandID, ioCommandKind, ioCommandContents.pb);
  1435.             break;
  1436.         case kWriteCommand:
  1437.             status = DriverWriteCmd (addressSpaceID, ioCommandID, ioCommandKind, ioCommandContents.pb);
  1438.             break;
  1439.         case kKillIOCommand:            /* Always immediate */
  1440.             status = DriverKillIOCmd (ioCommandContents.pb);
  1441.             break;
  1442.         default:
  1443.             status = paramErr;
  1444.             break;
  1445.     }
  1446.     if ((ioCommandKind & kImmediateIOCommandKind) != 0) {
  1447.         /* Immediate commands return the operation status and don't call IOCommandIsComplete */
  1448.     } else if (status == ioInProgress) {
  1449.         /* Perform the action and call IOCommandIsComplete at some later time */
  1450.         status = noErr;
  1451.     } else {
  1452.         err = status;
  1453.         status = IOCommandIsComplete (ioCommandID, err);
  1454.     }
  1455.  
  1456. #if DEBUG
  1457.     if (err == paramErr) {
  1458.         SysDebugStr ("\p!!Param Error in DoDriverIO!!");
  1459.     }
  1460. #if FULLDEBUG
  1461.     SysDebugStr ("\pleaving DoDriverIO;g");
  1462. #endif
  1463. #endif
  1464.  
  1465.     return (status);
  1466. }
  1467.  
  1468. static pascal void HWIntProc (QElemPtr passedPtr) {
  1469.     UInt32                    numSamples,
  1470.                             numBytesLeftToRecord;
  1471.     Boolean                    recordingComplete    = false;
  1472.     ParmBlkPtr                pb = ((myTMTask*)passedPtr)->pb;
  1473.  
  1474. #if DEBUG
  1475.     SysDebugStr ("\pin HWIntProc");
  1476. #endif
  1477.  
  1478.     if (gStopRecording == false) {
  1479.         numBytesLeftToRecord = pb->ioParam.ioReqCount - pb->ioParam.ioActCount;
  1480.  
  1481.         //If the number of bytes requested is larger than our buffer, return the max number of samples that will fit in our buffer
  1482.         if (numBytesLeftToRecord > (kSamplesInBuffer * gNumberChannels * (gSampleSize/8))) {
  1483.             numSamples = kSamplesInBuffer;
  1484.         } else {
  1485.             //otherwise figure out how many samples the requested number of bytes equals
  1486.             numSamples = numBytesLeftToRecord / (gNumberChannels * (gSampleSize/8));
  1487.         }
  1488.  
  1489.         switch (gCurrentInputSource) {
  1490.             case 1:
  1491.                 //Make a square wave
  1492.                 MakeSquareWave (0, numSamples, gSampleRate, 1000, gSampleSize, gNumberChannels);
  1493.                 break;
  1494.             case 2:
  1495.                 //Make a saw tooth wave
  1496.                 MakeSawWave (0, numSamples, gSampleRate, 1000, gSampleSize, gNumberChannels);
  1497.                 break;
  1498.             case 3:
  1499.                 //Make silence
  1500.                 MakeSquareWave (0, numSamples, gSampleRate, 0, gSampleSize, gNumberChannels);
  1501.                 break;
  1502.             default:
  1503.             #if DEBUG
  1504.                 SysDebugStr ("\punknown input source in HWIntProc");
  1505.             #endif
  1506.                 break;    //null statement so when DEBUG is false this switch still compiles
  1507.         }
  1508.  
  1509.         if (gTwosComplementOn == true && gSampleSize == 8) {
  1510.             SInt32 i;
  1511.             for (i = 0; i < numSamples; i++) {
  1512.                 ((UInt32*)gSoundBuffer)[i] ^= 0x80808080;
  1513.             }
  1514.         }
  1515.  
  1516.         if (gUserInterruptProc != nil) {
  1517.             CallSIInterruptProc (gUserInterruptProc, pb, gSoundBuffer, 0, gSampleSize);
  1518.         }
  1519.  
  1520.         //if we have a buffer and pausing is off, copy data to app's buffer
  1521.         if (pb->ioParam.ioBuffer != nil && gPauseState == 0) {
  1522.             BlockMoveData (gSoundBuffer, pb->ioParam.ioBuffer+pb->ioParam.ioActCount, numSamples*(gSampleSize/8)*gNumberChannels);
  1523.         }
  1524.  
  1525.         //If we are not paused, update the number of samples we have made
  1526.         if (gPauseState == 0) {
  1527.             pb->ioParam.ioActCount += numSamples*(gSampleSize/8)*gNumberChannels;
  1528.         }
  1529.  
  1530.         if (pb->ioParam.ioActCount == pb->ioParam.ioReqCount) {
  1531.             recordingComplete = true;
  1532.         }
  1533.     }
  1534.  
  1535.     if (recordingComplete == false && gStopRecording == false) {
  1536.         PrimeTime ((QElemPtr)passedPtr, gInterruptFreq);    //more data to record
  1537.     } else {
  1538.         //Have recorded requested number of bytes, stop the hardware (if continuous recording is not on)
  1539.         //Do a software interrupt so that we can call IOCommandIsComplete (which can only be called at
  1540.         //task level and software interrupt level.
  1541.         RmvTime ((QElemPtr)passedPtr);
  1542.         if (gStopRecording == true) {
  1543.             SetHardwareToDefault ();
  1544.         } else if (gContinuousOn == false) {
  1545.             gSamplesWritten = 0;
  1546.         }
  1547.         IOCommandIsComplete ((IOCommandID)pb->ioParam.ioCmdAddr, noErr);
  1548.     }
  1549.  
  1550. #if FULLDEBUG
  1551.     SysDebugStr ("\pleaving HWIntProc;g");
  1552. #endif
  1553. }
  1554.  
  1555. //Makes a square wave of the specified frequency and duration
  1556. //duration in 1/100 of a second, i.e. 500 for a five second tone
  1557. //frequency in samples per second, i.e. 8000 for an 8000Hz square wave (requires 16kHz sampling rate)
  1558. static void MakeSquareWave (SInt32 duration, SInt32 numberSamples, UnsignedFixed sampleRate, SInt32 frequency, SInt16 sampleSize, SInt16 numChannels) {
  1559.     SInt32            numSamples    = 0;
  1560.  
  1561.     if (duration != 0 && numberSamples == 0) {
  1562.         numSamples = (duration / 100.0) * (sampleRate >> 16);
  1563.     } else if (duration == 0 && numberSamples != 0) {
  1564.         numSamples = numberSamples;
  1565.     }
  1566.  
  1567.     if (numSamples > 0) {
  1568.         if (frequency == 0) {
  1569.             //Generate silence of requested length
  1570.             if (sampleSize == 8) {
  1571.                 UInt8 *buffer8 = (UInt8*)gSoundBuffer;
  1572.                 UInt8 *end8 = buffer8 + (numSamples * numChannels);
  1573.                 while (buffer8 < end8) {
  1574.                     *buffer8++ = kSilence;
  1575.                 }
  1576.             } else if (sampleSize == 16) {
  1577.                 UInt16 *buffer16 = (UInt16*)gSoundBuffer;
  1578.                 UInt16 *end16 = buffer16 + (numSamples * numChannels);
  1579.                 while (buffer16 < end16) {
  1580.                     *buffer16++ = 0;
  1581.                 }
  1582.             } else {
  1583.             #if DEBUG
  1584.                 SysDebugStr ("\pbad sample size in MakeSquareWave (silence)");
  1585.             #endif
  1586.             }
  1587.         } else if ((frequency * 2) <= sampleRate) {
  1588.             //Generate a square wave
  1589.             SInt32    samplesBeforeReverse =     (((sampleRate >> 16) / frequency) / 2) * numChannels;
  1590.  
  1591.             if (sampleSize == 8) {
  1592.                 UInt8 *buffer8 = (UInt8*)gSoundBuffer;
  1593.                 UInt8 *end8 = buffer8 + (numSamples * numChannels);
  1594.                 while (buffer8 < end8) {
  1595.                     if (gSamplesWritten < samplesBeforeReverse) {
  1596.                         *buffer8++ = kSilence + kAmplitude;
  1597.                         gSamplesWritten++;
  1598.                     } else {
  1599.                         *buffer8++ = kSilence - kAmplitude;
  1600.                         if (gSamplesWritten == (samplesBeforeReverse * 2 - 1)) {
  1601.                             gSamplesWritten = 0;
  1602.                         } else {
  1603.                             gSamplesWritten++;
  1604.                         }
  1605.                     }
  1606.                 }
  1607.             } else if (sampleSize == 16) {
  1608.                 UInt16 *buffer16 = (UInt16*)gSoundBuffer;
  1609.                 UInt16 *end16 = buffer16 + (numSamples * numChannels);
  1610.                 while (buffer16 < end16) {
  1611.                     if (gSamplesWritten < samplesBeforeReverse) {
  1612.                         *buffer16++ = (kAmplitude * 0.01) * 32767;
  1613.                         gSamplesWritten++;
  1614.                     } else {
  1615.                         *buffer16++ = -((kAmplitude * 0.01) * 32767);
  1616.                         if (gSamplesWritten == (samplesBeforeReverse * 2 - 1)) {
  1617.                             gSamplesWritten = 0;
  1618.                         } else {
  1619.                             gSamplesWritten++;
  1620.                         }
  1621.                     }
  1622.                 }
  1623.             } else {
  1624.             #if DEBUG
  1625.                 SysDebugStr ("\pbad sample size in MakeSquareWave (square wave)");
  1626.             #endif
  1627.             }
  1628.         }
  1629.     }
  1630. }
  1631.  
  1632. static void MakeSawWave (SInt32 duration, SInt32 numberSamples, UnsignedFixed sampleRate, SInt32 frequency, SInt16 sampleSize, SInt16 numChannels) {
  1633.     SInt32            numSamples    = 0;
  1634.  
  1635.     if (duration != 0 && numberSamples == 0) {
  1636.         numSamples = (duration / 100.0) * (sampleRate >> 16);
  1637.     } else if (duration == 0 && numberSamples != 0) {
  1638.         numSamples = numberSamples;
  1639.     }
  1640.  
  1641.     if (numSamples > 0) {
  1642.         if ((frequency * 2) <= sampleRate) {
  1643.             //Generate a saw tooth wave
  1644.             SInt32    samplesBeforeReverse =     (((sampleRate >> 16) / frequency) / 2);
  1645.  
  1646.             if (sampleSize == 8) {
  1647.                 UInt8 *buffer8 = (UInt8*)gSoundBuffer;
  1648.                 UInt8 *end8 = buffer8 + (numSamples * numChannels);
  1649.                 UInt8 increment = (kAmplitude*2) / samplesBeforeReverse;
  1650.                 while (buffer8 < end8) {
  1651.                     if (gSamplesWritten < samplesBeforeReverse) {
  1652.                         *buffer8++ = gNextSaw8Sample;
  1653.                         if (numChannels == 2) {
  1654.                             *buffer8++ = gNextSaw8Sample;
  1655.                         }
  1656.                         gNextSaw8Sample += increment;
  1657.                         gSamplesWritten++;
  1658.                     } else {
  1659.                         *buffer8++ = gNextSaw8Sample;
  1660.                         if (numChannels == 2) {
  1661.                             *buffer8++ = gNextSaw8Sample;
  1662.                         }
  1663.                         gNextSaw8Sample -= increment;
  1664.                         if (gSamplesWritten == (samplesBeforeReverse * 2 - 1)) {
  1665.                             gSamplesWritten = 0;
  1666.                         } else {
  1667.                             gSamplesWritten++;
  1668.                         }
  1669.                     }
  1670.                 }
  1671.             } else if (sampleSize == 16) {
  1672.                 UInt16 *buffer16 = (UInt16*)gSoundBuffer;
  1673.                 UInt16 *end16 = buffer16 + (numSamples * numChannels);
  1674.                 UInt16 increment = (((kAmplitude * 0.01) * 32767)*2) / samplesBeforeReverse;
  1675.                 while (buffer16 < end16) {
  1676.                     if (gSamplesWritten < samplesBeforeReverse) {
  1677.                         *buffer16++ = gNextSaw16Sample;
  1678.                         if (numChannels == 2) {
  1679.                             *buffer16++ = gNextSaw16Sample;
  1680.                         }
  1681.                         gNextSaw16Sample += increment;
  1682.                         gSamplesWritten++;
  1683.                     } else {
  1684.                         *buffer16++ = gNextSaw16Sample;
  1685.                         if (numChannels == 2) {
  1686.                             *buffer16++ = gNextSaw16Sample;
  1687.                         }
  1688.                         gNextSaw16Sample -= increment;
  1689.                         if (gSamplesWritten == (samplesBeforeReverse * 2 - 1)) {
  1690.                             gSamplesWritten = 0;
  1691.                         } else {
  1692.                             gSamplesWritten++;
  1693.                         }
  1694.                     }
  1695.                 }
  1696.             } else {
  1697.             #if DEBUG
  1698.                 SysDebugStr ("\pbad sample size in MakeSawWave");
  1699.             #endif
  1700.             }
  1701.         }
  1702.     }
  1703. }
  1704.  
  1705. static OSErr        DoOptionsDialog    (void) {
  1706.     FSSpec                driverFSSpec;
  1707.     Rect                rect;
  1708.     ControlHandle        item        = nil;
  1709.     DialogRef            optionsDialog;
  1710.     OSErr                err;
  1711.     SInt16                itemHit        = 0,
  1712.                         itemType,
  1713.                         curRes,
  1714.                         resRef        = -1,
  1715.                         newInputSource = gCurrentInputSource;
  1716.     Boolean                wasChanged,
  1717.                         done        = false;
  1718.  
  1719.     curRes = CurResFile ();
  1720.     err = ResolveAlias (nil, gAliasToDriver, &driverFSSpec, &wasChanged);
  1721.     if (err == noErr) {
  1722.         resRef = FSpOpenResFile (&driverFSSpec, fsRdPerm);
  1723.         if (resRef != -1) {
  1724.             optionsDialog = GetNewDialog (128, nil, (GrafPtr)-1L);
  1725.         } else {
  1726.         #if DEBUG
  1727.             SysDebugStr ("\pFSpOpenResFile failed");
  1728.         #endif
  1729.         }
  1730.     } else {
  1731.     #if DEBUG
  1732.         SysDebugStr ("\pResolveAlias failed");
  1733.     #endif
  1734.     }
  1735.  
  1736.     if (optionsDialog != nil) {
  1737.         //gCurrentInputSource+5 is the item number of the corresponding radio buttons
  1738.         //so itemHit-5 is the input source number
  1739.         GetDialogItem (optionsDialog, gCurrentInputSource+5, &itemType, &(Handle)item, &rect);
  1740.         if (item != nil) {
  1741.             SetControlValue (item, 1);
  1742.             SetDialogDefaultItem (optionsDialog, 1);    //put the ring around the OK button
  1743.         } else {
  1744.         #if DEBUG
  1745.             SysDebugStr ("\pitem is nil!");
  1746.         #endif
  1747.         }
  1748.  
  1749.         ShowWindow (optionsDialog);
  1750.  
  1751.         do {
  1752.             ModalDialog (nil, &itemHit);
  1753.             switch (itemHit) {
  1754.                 case 1:        //OK button
  1755.                     gCurrentInputSource = newInputSource;
  1756.                     done = true;
  1757.                     break;
  1758.                 case 2:        //Cancel button
  1759.                     done = true;
  1760.                     break;
  1761.                 case 6:        //Square wave
  1762.                 case 7:        //Saw wave
  1763.                 case 8:        //Silence
  1764.                     newInputSource = itemHit-5;
  1765.                     GetDialogItem (optionsDialog, 6, &itemType, &(Handle)item, &rect);
  1766.                     SetControlValue (item, itemHit == 6);
  1767.                     GetDialogItem (optionsDialog, 7, &itemType, &(Handle)item, &rect);
  1768.                     SetControlValue (item, itemHit == 7);
  1769.                     GetDialogItem (optionsDialog, 8, &itemType, &(Handle)item, &rect);
  1770.                     SetControlValue (item, itemHit == 8);
  1771.                     break;
  1772.             }
  1773.         } while (!done);
  1774.  
  1775.         DisposeDialog (optionsDialog);
  1776.         optionsDialog = nil;
  1777.     } else {
  1778.     #if DEBUG
  1779.         SysDebugStr ("\poptionsDialog is nil!");
  1780.     #endif
  1781.     }
  1782.  
  1783.     if (resRef != -1) {
  1784.         CloseResFile (resRef);
  1785.         UseResFile (curRes);
  1786.     }
  1787.  
  1788.     return err;
  1789. }
  1790.  
  1791. static void SetHardwareToDefault (void) {
  1792.     gContinuousOn            = 0;
  1793.     gLevelMeterOn            = 0;
  1794.     gTwosComplementOn        = 0;
  1795.     gAGCOn                    = 0;
  1796.     gPlayThruVolume            = 0;
  1797.     gVoxRecordingOn            = 0;
  1798.     gVoxStoppingOn            = 0;
  1799.     gPauseState                = 0;
  1800.     gNumberChannels            = 1;
  1801.     gSampleSize                = 8;
  1802.     gVOXStartTrigger        = 0;
  1803.     gVOXStopTrigger            = 0;
  1804.     gVOXDelay                = 0;
  1805.     gCompressionFactor        = 1;
  1806. //    gCurrentInputSource        = 1;    //don't change the current input source
  1807.     gActiveChannels            = 0x00000001;
  1808.     gSampleRate                = rate22050hz;
  1809.     gInputGain                = 0x00010000;
  1810.     gLeftInputGain            = 0x01000100;
  1811.     gRightInputGain            = 0x01000100;
  1812.     gCompressionType        = 'NONE';
  1813.     gRecordingQuality        = siBestQuality;
  1814.     gUserInterruptProc        = nil;
  1815.     gSamplesWritten            = 0;
  1816.     gNextSaw8Sample            = kSilence - kAmplitude;
  1817.     gNextSaw16Sample        = -((kAmplitude * 0.01) * 32767);
  1818.     gStopRecording            = false;
  1819. }
  1820.  
  1821.